/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.icee.myth.server.fighter;

import com.icee.myth.server.skill.Skill;
import com.icee.myth.server.battle.Battle;
import com.icee.myth.server.battle.BattleMessageType;
import com.icee.myth.protobuf.BattleProtocol.BeEffectProto;
import com.icee.myth.protobuf.ExternalCommonProtocol.FighterProto;
import com.icee.myth.server.card.CardStaticInfo;
import com.icee.myth.server.reward.RewardItemInfo;
import com.icee.myth.server.skill.Skills;
import com.icee.myth.server.talent.TalentStaticInfo;
import com.icee.myth.utils.Consts;
import com.icee.myth.utils.RandomGenerator;

/**
 * Actor仅存在与战斗中，Actor的种类有Hero、soldier、monster
 * 实现通用的行走和攻击逻辑，包括：普通攻击、追击、技能使用等
 * @author liuxianke
 */
public class Fighter {
    public final int id;   // Actor的id（即所在战场中的位置）

    public final CardStaticInfo cardStaticInfo; // 卡片信息
    public final Battle battle;  // 战斗引用，当有战斗关联时角色所产生的网络包存放到battle中
    
    public int skillCooldown;   // 技能冷却

    public final long maxHp;  // 最大血量
    public long curHp;  // 当前血量

    public final int atk;     // 攻击
    public final int dex;     // 机动
    
    public final int hit;     // 命中（千分比）
    public final int cri;     // 暴击（千分比）
    public final int dod;     // 闪避（千分比）
    public final int ten;     // 韧性（千分比）

    public final float cureUp;  // 治疗效率
    public final float damResP; // 物伤减免
    public final float damResM; // 魔伤减免

    private Skill normalSkill;   // 普通技能
    private Skill specialSkill;  // 特殊技能

    private final int dropMultiple;   // 卡片掉落倍率（0表示不掉落）
    private final boolean isBoss;     // 是否boss（大卡）

    public Fighter(int id,
            Battle battle,
            CardStaticInfo cardStaticInfo,
            int level,
            long curHP,
            TalentStaticInfo leaderTalentStaticInfo,
            TalentStaticInfo helperTalentStaticInfo,
            boolean isBoss,
            int dropMultiple,    // 掉卡倍率
            float hpChange,     // 生命增强
            float atkChange,    // 攻击增强
            int criAndTenChange,// 暴击和韧性增强
            int hitAndDodChange // 队伍命中能力和闪避增长
            ) {
        this.id = id;
        this.battle = battle;
        this.cardStaticInfo = cardStaticInfo;

        if (cardStaticInfo.normalSkillId != 0) {
            normalSkill = Skills.INSTANCE.getSkill(cardStaticInfo.normalSkillId);
        }

        if (cardStaticInfo.specialSkillId != 0) {
            specialSkill = Skills.INSTANCE.getSkill(cardStaticInfo.specialSkillId);
            skillCooldown = cardStaticInfo.specialSkillPrepare;
        }

        // 计算队长天赋和助战者天赋影响
        float hpSkill = 1f;
        float atkSkill = 1f;
        float dexSkill = 1f;
        int hitSkill = 0;
        int criSkill = 0;
        int dodSkill = 0;
        int tenSkill = 0;
        int cureUpSkill = 0;
        int damResPSkill = 0;
        int damResMSkill = 0;
        if ((leaderTalentStaticInfo!=null) && ((leaderTalentStaticInfo.campMask & (1<<cardStaticInfo.camp)) != 0) && ((leaderTalentStaticInfo.typeMask & (1L<<cardStaticInfo.type)) != 0)) {
            hpSkill += leaderTalentStaticInfo.hpSkill;
            atkSkill += leaderTalentStaticInfo.atkSkill;
            dexSkill += leaderTalentStaticInfo.dexSkill;
            hitSkill += leaderTalentStaticInfo.hitSkill;
            criSkill += leaderTalentStaticInfo.criSkill;
            dodSkill += leaderTalentStaticInfo.dodSkill;
            tenSkill += leaderTalentStaticInfo.tenSkill;
            cureUpSkill += leaderTalentStaticInfo.cureUpSkill;
            damResPSkill += leaderTalentStaticInfo.damResPSkill;
            damResMSkill += leaderTalentStaticInfo.damResMSkill;
        }
        if ((helperTalentStaticInfo!=null) && ((helperTalentStaticInfo.campMask & (1<<cardStaticInfo.camp)) != 0) && ((helperTalentStaticInfo.typeMask & (1L<<cardStaticInfo.type)) != 0)) {
            hpSkill += helperTalentStaticInfo.hpSkill;
            atkSkill += helperTalentStaticInfo.atkSkill;
            dexSkill += helperTalentStaticInfo.dexSkill;
            hitSkill += helperTalentStaticInfo.hitSkill;
            criSkill += helperTalentStaticInfo.criSkill;
            dodSkill += helperTalentStaticInfo.dodSkill;
            tenSkill += helperTalentStaticInfo.tenSkill;
            cureUpSkill += helperTalentStaticInfo.cureUpSkill;
            damResPSkill += helperTalentStaticInfo.damResPSkill;
            damResMSkill += helperTalentStaticInfo.damResMSkill;
        }

        maxHp = (long) ((cardStaticInfo.HPBase + cardStaticInfo.HPGrow * level) * hpSkill * hpChange);
        atk = (int) ((cardStaticInfo.ATKBase + cardStaticInfo.ATKGrow * level) * atkSkill * atkChange);
        dex = (int) ((cardStaticInfo.DEXBase + cardStaticInfo.DEXGrow * level) * dexSkill);
        this.curHp = (curHP > maxHp)?maxHp:curHP;

        hit = cardStaticInfo.HITBase + hitSkill + hitAndDodChange;
        cri = cardStaticInfo.CRIBase + criSkill + criAndTenChange;
        dod = cardStaticInfo.DODBase + dodSkill + hitAndDodChange;
        ten = cardStaticInfo.TENBase + tenSkill + criAndTenChange;

        cureUp = cardStaticInfo.cureUpBase + cureUpSkill;
        damResP = cardStaticInfo.damResPBase + damResPSkill;
        damResM = cardStaticInfo.damResMBase + damResMSkill;

        this.dropMultiple = dropMultiple;
        this.isBoss = isBoss;
    }

    public void action() {
        if (specialSkill != null) {
            skillCooldown--;

            if (skillCooldown < 0) {
                specialSkill.action(this);
                skillCooldown = cardStaticInfo.specialSkillCycle;
            } else if (normalSkill != null) {
                normalSkill.action(this);
            }
        } else if (normalSkill != null) {
            normalSkill.action(this);
        }
    }

    public void beAttack(Fighter attacker,        // 攻击者
            int attackType,     // 攻击类型（命中/暴击/躲闪/格挡）
            long minusHp,      // 攻击伤血
            int skillId,        // 攻击技能的ID
            int hitPoint        // 技能打击点号
            ) {
        long realMinusHp = (minusHp > curHp)?curHp:minusHp;
        
        curHp -= realMinusHp;

        RewardItemInfo rewardItemInfo = null;
        if ((dropMultiple > 0) && (curHp == 0)) {
            // 在指定的掉落次数内掉不到卡则重新掉
            int times = dropMultiple;
            do {
                // 计算掉落
                if (cardStaticInfo.rewardGroupInfo != null) {
                    int rand = RandomGenerator.INSTANCE.generator.nextInt(10000);
                    for (int i=0; i<cardStaticInfo.rewardGroupInfo.rewardItems.length; i++) {
                        if (rand < cardStaticInfo.rewardGroupInfo.rewardItems[i].propability) {
                            rewardItemInfo = cardStaticInfo.rewardGroupInfo.rewardItems[i].itemInfo;
                            battle.addRewardItemInfo(rewardItemInfo);
                            break;
                        }
                    }
                }
                
                times--;
            } while ((times > 0) &&
                     ((rewardItemInfo == null) ||
                      (rewardItemInfo.itemType != Consts.REWARD_ITEM_TYPE_CARD)));
        }

        if (battle.needBuildProto) {
            battle.addBattleMessage(BattleMessageType.BEATTACK, buildBeEffectProto(attacker, attackType, minusHp, skillId, hitPoint, rewardItemInfo).toByteString());
        }
    }

    public void beCure(Fighter doctor,
                        int cureType,
                        long cureHp,
                        int skillId,
                        int hitPoint
                       ) {
        long maxAddHp = maxHp - curHp;
        long realAddHp = maxAddHp>cureHp?cureHp:maxAddHp;

        curHp += realAddHp;

        if (battle.needBuildProto) {
            battle.addBattleMessage(BattleMessageType.BECURE, buildBeEffectProto(doctor, cureType, cureHp, skillId, hitPoint, null).toByteString());
        }
    }

    // 恢复（用于胜率计算）
    public void recover() {
        curHp = maxHp;
    }

    public FighterProto buildFighterProto() {
        FighterProto.Builder builder = FighterProto.newBuilder();
        builder.setId(id);
        builder.setCardId(cardStaticInfo.id);
        builder.setMaxHp(maxHp);
        builder.setHp(curHp);
        builder.setIsBoss(isBoss);
        
        return builder.build();
    }

    private BeEffectProto buildBeEffectProto(Fighter doctor, int cureType, long changeHp, int skillId, int hitPoint, RewardItemInfo rewardItemInfo) {
        BeEffectProto.Builder builder = BeEffectProto.newBuilder();

        builder.setActorId(id);
        builder.setCasterId(doctor.id);
        builder.setType(cureType);
        builder.setChangeHp(changeHp);
        builder.setCurHp(curHp);
        builder.setSkillId(skillId);
        builder.setHitPoint(hitPoint);

        if (rewardItemInfo != null) {
            builder.setReward(rewardItemInfo.buildRewardItemProto());
        }

        return builder.build();
    }
}
